package BLC

import (
	"bytes"
	"crypto/sha256"
	"encoding/gob"
	"fmt"
	"log"
	"time"
)

type Block struct{
	//区块的高度
	Height int64
	//时间戳，创建区块的时间
	TimeStamp int64
	//上一个区块的hash，父hash
	PreviewHash []byte
	//交易数据
	Transactions []*Transaction
	//hash当前区块的hash
	Hash []byte
	//区块的nonce的值
	Nonce int
}



func NewBlock(transactions []*Transaction,Height int64,previewHash []byte)*Block{
	b:=&Block{
		Height:Height,
		TimeStamp:time.Now().Unix(),
		PreviewHash:previewHash,
		Transactions:transactions,
		Hash:[]byte{},
		Nonce:0,
	}
	p:=NewProofOfWork(b)
	nonce,hash:=p.Run()
	b.Hash=hash
	b.Nonce=nonce

	return b
}

func NewGenisBlock(coinbase *Transaction)*Block{
	return NewBlock([]*Transaction{coinbase},0,[]byte{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0})
}


//把区块序列化成字节数组
func (b *Block)SerilizeBlock()[]byte{
	var buff bytes.Buffer

	encoder:=gob.NewEncoder(&buff)
	err:=encoder.Encode(b)

	if err!=nil{
		log.Panic(err)
	}

	return buff.Bytes()
}

//把字节数组反序列化成block
func UnSerilizeBlock(d []byte)*Block{
	var block Block

	decode:=gob.NewDecoder(bytes.NewReader(d))
	err:=decode.Decode(&block)

	if err!=nil{
		log.Panic(err)
	}

	return &block
}

//下面的这个方法是提供给挖矿的时候使用的
//将区块的所有的交易的id进行拼接，生成hash
func (b *Block)HashTransactions()[]byte{
	var txHashes [][]byte
	var txHash [32]byte

	for _,tx:=range b.Transactions{
		txHashes=append(txHashes,tx.ID)
	}

	txHash=sha256.Sum256(bytes.Join(txHashes,[]byte{}))
	return txHash[:]
}




func (b *Block)Print(){
	fmt.Printf("当前区块的高度是:%d\n",b.Height)
	fmt.Printf("时间戳是:%s\n",time.Unix(b.TimeStamp,0).Format("2006-01-02 15:04:05.999999999"))
	fmt.Printf("前一个区块的hash是:%x\n",b.PreviewHash)
	fmt.Printf("当前区块的hash是:%x\n",b.Hash)
	fmt.Printf("当前区块的Nonce是:%d\n",b.Nonce)

	for _,tx:=range b.Transactions{
		fmt.Printf("交易的hash是:%x\n",tx.ID)

		fmt.Println("转账输入是:")
		for _,vins:=range tx.Vin{
			fmt.Printf("来自%x区块,金额%d,代币所有者的签名%s\n",vins.Txid,vins.Vout,vins.ScriptSig)
		}

		fmt.Println("转账输出是:")
		for _,vout:=range tx.Vout{
			fmt.Printf("金额%d,代币所有者的签名%s\n",vout.Value,vout.ScriptPublic)
		}

	}
}


